//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package project_issue_api_serv

import (
	"context"

	"atomgit.com/openlinksaas-org/api-server/api_common"
	"atomgit.com/openlinksaas-org/api-server/dao"
	"atomgit.com/openlinksaas-org/api-server/dao/issue_dao"
	"atomgit.com/openlinksaas-org/api-server/utils"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/notices/notices_issue"
	"atomgit.com/openlinksaas-org/proto-gen-go.git/project_issue_api"
	"go.mongodb.org/mongo-driver/mongo"
)

// 增加依赖
func (apiImpl *ProjectIssueApiImpl) AddDependence(ctx context.Context, req *project_issue_api.AddDependenceRequest) (*project_issue_api.AddDependenceResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_issue_api.AddDependenceResponse{
			Code:   project_issue_api.AddDependenceResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_issue_api.AddDependenceResponse{
			Code:   project_issue_api.AddDependenceResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_issue_api.AddDependenceResponse{
			Code:   project_issue_api.AddDependenceResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_issue_api.AddDependenceResponse{
			Code:   project_issue_api.AddDependenceResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	if req.IssueId == req.DependIssueId {
		return &project_issue_api.AddDependenceResponse{
			Code:   project_issue_api.AddDependenceResponse_CODE_NOT_DEPEND_SELF,
			ErrMsg: "依赖和被依赖工单相同",
		}, nil
	}

	issueItem, err := issue_dao.IssueDao.Get(ctx, req.ProjectId, req.IssueId)
	if err != nil {
		return &project_issue_api.AddDependenceResponse{
			Code:   project_issue_api.AddDependenceResponse_CODE_NO_ISSUE,
			ErrMsg: "工单不存在",
		}, nil
	}
	//只有管理员和相关人员可以创建子工单
	if !(sessionItem.UserId == projectItem.OwnerUserId || roleItem.BasicInfo.Admin || sessionItem.UserId == issueItem.CreateUserId ||
		sessionItem.UserId == issueItem.ExecUserId || sessionItem.UserId == issueItem.CheckUserId) {
		return &project_issue_api.AddDependenceResponse{
			Code:   project_issue_api.AddDependenceResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	dependIssueItem, err := issue_dao.IssueDao.Get(ctx, req.ProjectId, req.DependIssueId)
	if err != nil {
		return &project_issue_api.AddDependenceResponse{
			Code:   project_issue_api.AddDependenceResponse_CODE_NO_DEPEND_ISSUE,
			ErrMsg: "依赖工单不存在",
		}, nil
	}

	newDependMeCount := uint32(0)

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = issue_dao.DependDao.Insert(sessCtx, &issue_dao.DependDbItem{
			ProjectId:     req.ProjectId,
			IssueId:       req.IssueId,
			DependIssueId: req.DependIssueId,
		})
		if err != nil {
			return nil, err
		}
		dependMeIdList, err := issue_dao.DependDao.DistinctByDependIssue(sessCtx, req.ProjectId, req.DependIssueId)
		if err != nil {
			return nil, err
		}
		err = issue_dao.IssueDao.UpdateDependMeCount(sessCtx, req.ProjectId, req.DependIssueId, len(dependMeIdList))
		if err != nil {
			return nil, err
		}
		newDependMeCount = uint32(len(dependMeIdList))
		return &project_issue_api.AddDependenceResponse{
			Code: project_issue_api.AddDependenceResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//记录事件
	go apiImpl.addAddDependenceEvent(sessionItem, projectItem, issueItem, dependIssueItem)
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_issue.UpdateIssueDepNotice{
		ProjectId:  req.ProjectId,
		IssueId:    req.IssueId,
		DepIssueId: req.DependIssueId,
	})
	go apiImpl.checkDependMe(req.ProjectId, req.DependIssueId, uint32(issueItem.IssueType), newDependMeCount)
	return ret.(*project_issue_api.AddDependenceResponse), nil
}

// 删除依赖
func (apiImpl *ProjectIssueApiImpl) RemoveDependence(ctx context.Context, req *project_issue_api.RemoveDependenceRequest) (*project_issue_api.RemoveDependenceResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_issue_api.RemoveDependenceResponse{
			Code:   project_issue_api.RemoveDependenceResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_issue_api.RemoveDependenceResponse{
			Code:   project_issue_api.RemoveDependenceResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_issue_api.RemoveDependenceResponse{
			Code:   project_issue_api.RemoveDependenceResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_issue_api.RemoveDependenceResponse{
			Code:   project_issue_api.RemoveDependenceResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	issueItem, err := issue_dao.IssueDao.Get(ctx, req.ProjectId, req.IssueId)
	if err != nil {
		return &project_issue_api.RemoveDependenceResponse{
			Code:   project_issue_api.RemoveDependenceResponse_CODE_NO_ISSUE,
			ErrMsg: "工单不存在",
		}, nil
	}
	//只有管理员和相关人员可以创建子工单
	if !(sessionItem.UserId == projectItem.OwnerUserId || roleItem.BasicInfo.Admin || sessionItem.UserId == issueItem.CreateUserId ||
		sessionItem.UserId == issueItem.ExecUserId || sessionItem.UserId == issueItem.CheckUserId) {
		return &project_issue_api.RemoveDependenceResponse{
			Code:   project_issue_api.RemoveDependenceResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	dependIssueItem, err := issue_dao.IssueDao.Get(ctx, req.ProjectId, req.DependIssueId)
	if err != nil {
		return &project_issue_api.RemoveDependenceResponse{
			Code:   project_issue_api.RemoveDependenceResponse_CODE_NO_DEPEND_ISSUE,
			ErrMsg: "依赖工单不存在",
		}, nil
	}

	newDependMeCount := uint32(0)

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = issue_dao.DependDao.Remove(sessCtx, req.ProjectId, req.IssueId, req.DependIssueId)
		if err != nil {
			return nil, err
		}
		dependMeIdList, err := issue_dao.DependDao.DistinctByDependIssue(sessCtx, req.ProjectId, req.DependIssueId)
		if err != nil {
			return nil, err
		}
		err = issue_dao.IssueDao.UpdateDependMeCount(sessCtx, req.ProjectId, req.DependIssueId, len(dependMeIdList))
		if err != nil {
			return nil, err
		}
		newDependMeCount = uint32(len(dependMeIdList))
		return &project_issue_api.RemoveDependenceResponse{
			Code: project_issue_api.RemoveDependenceResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//记录事件
	go apiImpl.addRemoveDependenceEvent(sessionItem, projectItem, issueItem, dependIssueItem)
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_issue.UpdateIssueDepNotice{
		ProjectId:  req.ProjectId,
		IssueId:    req.IssueId,
		DepIssueId: req.DependIssueId,
	})
	go apiImpl.checkDependMe(req.ProjectId, req.DependIssueId, uint32(issueItem.IssueType), newDependMeCount)
	return ret.(*project_issue_api.RemoveDependenceResponse), nil
}

func (apiImpl *ProjectIssueApiImpl) ListMyDepend(ctx context.Context, req *project_issue_api.ListMyDependRequest) (*project_issue_api.ListMyDependResponse, error) {
	emptyList := []*project_issue_api.IssueInfo{}
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_issue_api.ListMyDependResponse{
			Code:      project_issue_api.ListMyDependResponse_CODE_WRONG_SESSION,
			ErrMsg:    "会话不存在",
			IssueList: emptyList,
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_issue_api.ListMyDependResponse{
			Code:      project_issue_api.ListMyDependResponse_CODE_NO_PROJECT,
			ErrMsg:    "项目不存在",
			IssueList: emptyList,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_issue_api.ListMyDependResponse{
			Code:      project_issue_api.ListMyDependResponse_CODE_NO_PERMISSION,
			ErrMsg:    "没有权限",
			IssueList: emptyList,
		}, nil
	} else if err != nil {
		return nil, err
	}

	exist, err := issue_dao.IssueDao.Exist(ctx, req.ProjectId, req.IssueId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &project_issue_api.ListMyDependResponse{
			Code:      project_issue_api.ListMyDependResponse_CODE_NO_ISSUE,
			ErrMsg:    "工单不存在",
			IssueList: emptyList,
		}, nil
	}

	myDependIssueIdList, err := issue_dao.DependDao.DistinctByIssue(ctx, req.ProjectId, req.IssueId)
	if err != nil {
		return nil, err
	}
	myDependIssueItemList, err := issue_dao.IssueDao.ListById(ctx, req.ProjectId, myDependIssueIdList)
	if err != nil {
		return nil, err
	}
	myDependIssueList, err := apiImpl.listIssue(ctx, sessionItem, projectItem, roleItem, myDependIssueItemList)
	if err != nil {
		return nil, err
	}
	return &project_issue_api.ListMyDependResponse{
		Code:      project_issue_api.ListMyDependResponse_CODE_OK,
		IssueList: myDependIssueList,
	}, nil
}

func (apiImpl *ProjectIssueApiImpl) ListDependMe(ctx context.Context, req *project_issue_api.ListDependMeRequest) (*project_issue_api.ListDependMeResponse, error) {
	emptyList := []*project_issue_api.IssueInfo{}
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_issue_api.ListDependMeResponse{
			Code:      project_issue_api.ListDependMeResponse_CODE_WRONG_SESSION,
			ErrMsg:    "会话不存在",
			IssueList: emptyList,
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_issue_api.ListDependMeResponse{
			Code:      project_issue_api.ListDependMeResponse_CODE_NO_PROJECT,
			ErrMsg:    "项目不存在",
			IssueList: emptyList,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_issue_api.ListDependMeResponse{
			Code:      project_issue_api.ListDependMeResponse_CODE_NO_PERMISSION,
			ErrMsg:    "没有权限",
			IssueList: emptyList,
		}, nil
	} else if err != nil {
		return nil, err
	}

	exist, err := issue_dao.IssueDao.Exist(ctx, req.ProjectId, req.IssueId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &project_issue_api.ListDependMeResponse{
			Code:      project_issue_api.ListDependMeResponse_CODE_NO_ISSUE,
			ErrMsg:    "工单不存在",
			IssueList: emptyList,
		}, nil
	}

	dependMeIssueIdList, err := issue_dao.DependDao.DistinctByDependIssue(ctx, req.ProjectId, req.IssueId)
	if err != nil {
		return nil, err
	}
	dependMeIssueItemList, err := issue_dao.IssueDao.ListById(ctx, req.ProjectId, dependMeIssueIdList)
	if err != nil {
		return nil, err
	}
	dependMeIssueList, err := apiImpl.listIssue(ctx, sessionItem, projectItem, roleItem, dependMeIssueItemList)
	if err != nil {
		return nil, err
	}

	return &project_issue_api.ListDependMeResponse{
		Code:      project_issue_api.ListDependMeResponse_CODE_OK,
		IssueList: dependMeIssueList,
	}, nil
}
